package command

import (
	"io"
	"xemo.top/docker/cli/cli/config/configfile"
	"xemo.top/docker/cli/cli/context/docker"
	"xemo.top/docker/cli/cli/context/store"
	"xemo.top/docker/cli/cli/streams"
	"xemo.top/docker/cli/internal/containerizedengine"
	clitypes "xemo.top/docker/cli/types"
	"xemo.top/docker/docker/api/types"
	"xemo.top/docker/docker/client"
	"xemo.top/docker/docker/pkg/term"
)

// NewDockerCli 返回一个DockerCli实例，其中应用了所有运算符。
// NewDockerCli returns a DockerCli instance with all operators applied on it.
// 默认情况下，它应用标准流、来自环境的内容信任和默认的容器化客户端构造函数操作
// It applies by default the standard streams, the content trust from environment and the default containerized client constructor operations.
func NewDockerCli(ops ...DockerCliOption) (*DockerCli, error) {
	cli := &DockerCli{}
	defaultOps := []DockerCliOption{
		WithContentTrustFromEnv(),
		WithContainerizedClient(containerizedengine.NewClient),
	}
	cli.contextStoreConfig = DefaultContextStoreConfig()
	ops = append(defaultOps, ops...)
	if err := cli.Apply(ops...); err != nil {
		return nil, err
	}
	if cli.out == nil || cli.in == nil || cli.err == nil {
		stdin, stdout, stderr := term.StdStreams()
		if cli.in == nil {
			cli.in = streams.NewIn(stdin)
		}
		if cli.out == nil {
			cli.out = streams.NewOut(stdout)
		}
		if cli.err == nil {
			cli.err = stderr
		}
	}
	return cli, nil
}

// Apply cli上的所有操作
// Apply all the operation on the cli
func (cli *DockerCli) Apply(ops ...DockerCliOption) error {
	for _, op := range ops {
		if err := op(cli); err != nil {
			return err
		}
	}
	return nil
}

// DockerCli 是docker命令行客户端的一个实例。
// DockerCli is an instance the docker command line client.
// 客户端的实例可以从NewDockerCli返回。
// Instances of the client can be returned from NewDockerCli.
type DockerCli struct {
	configFile            *configfile.ConfigFile
	in                    *streams.In
	out                   *streams.Out
	err                   io.Writer
	client                client.APIClient
	serverInfo            ServerInfo
	clientInfo            *ClientInfo
	contentTrust          bool
	newContainerizeClient func(string) (clitypes.ContainerizedClient, error)
	contextStore          store.Store
	currentContext        string
	dockerEndpoint        docker.Endpoint
	contextStoreConfig    store.Config
}

// ClientInfo 存储有关客户端支持功能的详细信息
// ClientInfo stores details about the supported features of the client
type ClientInfo struct {
	HasExperimental bool
	DefaultVersion  string
}

// ServerInfo 存储有关服务器支持的功能和平台的详细信息
// ServerInfo stores details about the supported features and platform fo the server
type ServerInfo struct {
	HasExperimental bool
	OSType          string
	BuildkitVersion types.BuilderVersion
}

// Err returns the writer used for stderr
func (cli *DockerCli) Err() io.Writer {
	return cli.err
}

var defaultStoreEndpoints = []store.NamedTypeGetter{
	store.EndpointTypeGetter(docker.DockerEndpoint, func() interface{} { return &docker.EndpointMeta{} }),
}

// DefaultContextStoreConfig 返回一个新的store.Config，其中配置了默认的一组终结点。
// DefaultContextStoreConfig returns a new store.Config with the default set of endpoints configured.
func DefaultContextStoreConfig() store.Config {
	return store.NewConfig(
		func() interface{} { return &DockerContext{} },
		defaultStoreEndpoints...,
	)
}
